package cn.itsource.user.service.impl;


import cn.itsource.basic.eum.PhoneRegisterCons;
import cn.itsource.basic.eum.WechatCons;
import cn.itsource.basic.util.AjaxResult;
import cn.itsource.basic.util.BusinessException;
import cn.itsource.basic.util.HttpClientUtils;
import cn.itsource.basic.util.MD5Utils;
import cn.itsource.user.domain.Logininfo;
import cn.itsource.user.domain.User;
import cn.itsource.user.domain.Wxuser;
import cn.itsource.user.dto.AccountDto;
import cn.itsource.user.dto.WechatBinderDto;
import cn.itsource.user.dto.WechatDto;
import cn.itsource.user.mapper.LogininfoMapper;
import cn.itsource.user.mapper.UserMapper;
import cn.itsource.user.mapper.WxuserMapper;
import cn.itsource.user.service.LoginService;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * <p>@Description:方法的用途</p>
 * <p>@param [entId, roleId, type, deptId, level, personStaffIds, latelyUserId] 参数列表</p>
 * <p>@return 返回值</p>
 * <p>@throws 抛出异常类型</p>
 * <p>@author 方法作者</p>
 * <p>@date 创建时间</p>
 */
@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private WxuserMapper wxuserMapper;
    @Autowired
    private UserMapper userMapper;

    @Override
    public AjaxResult account(AccountDto dto) {
        // 参数校验
        // 根据账号查询logininfo表数据 邮箱、手机、username都可以作为账号登录
        Logininfo logininfo = logininfoMapper.findByAccount(dto);
        if (null == logininfo) {
            throw new BusinessException("账号或者密码错误！");
        }
        // 验证他的密码是否正确
        String passParam = dto.getPassword(); // 这个只是一个数字
        String passMd5 = MD5Utils.encrypByMd5(logininfo.getSalt() + passParam);
        String passwordDb = logininfo.getPassword();
        if (StringUtils.isBlank(passwordDb) || StringUtils.isBlank(passMd5) || !passMd5.equals(passwordDb)) {
            throw new BusinessException("账号或者密码错误！");
        }
        // 获取登陆成功后 返回给前端的数据
        Map<String, Object> map = getMap(logininfo);
        return AjaxResult.me().success(map);
    }

    /**
     * 微信扫码登录接口
     * @param dto
     * @return
     */
    @Override
    public AjaxResult wechat(WechatDto dto) {
        //检验参数
        //1，获取code
        String code = dto.getCode();
        if (StringUtils.isBlank(code)){
            throw new BusinessException("code不能为空");
        }
        //2,拼接地址
        String url = String.format(WechatCons.SECOND, WechatCons.APPID, WechatCons.SECRET, code);
        if (StringUtils.isBlank(url)){
            throw new BusinessException("请求地址错误");
        }
       //3,获取json字符串
        String s = HttpClientUtils.httpGet(url);
        System.out.println(s);
        //4,json字符串转换为jsonduixiang
        JSONObject jsonObject = JSONObject.parseObject(s);
        System.out.println(jsonObject);
        //5,获取token和openid
        String accessToken = jsonObject.getString("access_token");
        String openid = jsonObject.getString("openid");
        if (StringUtils.isBlank(accessToken) || StringUtils.isBlank(openid)){
            throw new BusinessException("获取token和openid失败");
        }
        //6,根据openid去获取微信用户
        Wxuser wxuser = wxuserMapper.findWxUserByopenId(openid);
        //7,判断wxuser是否存在
       if (null != wxuser){ //wxuser不为空
           //获取logininfo
          Logininfo logininfo = logininfoMapper.findByuserId(wxuser.getUserId());
          //存到redis
           Map<String, Object> map = this.getMap(logininfo);
           return AjaxResult.me().success(map);
       }
        // 没有 则返回resultObj = nobinder
        StringBuffer sbr = new StringBuffer()
                .append("?accessToken=")
                .append(accessToken)
                .append("&openId=").append(openid);
        // 我们现在返回的是 success:false  msg:nobinder  resultObj:"?accessToken=xxxx&openid=yyy"
        return AjaxResult.me().fail("nobinder").setResultObj(sbr);
    }

    /**
     * 微信绑定接口
     * @param dto
     * @return
     */
    @Override
    public AjaxResult binder(WechatBinderDto dto) {
        //从redis中获取验证码
        String phoneCode = (String) redisTemplate.opsForValue().get(String.format(PhoneRegisterCons.BINDER_CODE_KEY, dto.getPhone()));
        //校验验证码
        if (StringUtils.isBlank(phoneCode ) || !dto.getVerifyCode().equals(phoneCode)){
            throw new BusinessException("验证码错误。。。");
        }
        //根据token和openid调用第三个接口
        String url = String.format(WechatCons.THIRD, dto.getAccessToken(), dto.getOpenId());
        String s = HttpClientUtils.httpGet(url);
        if (StringUtils.isBlank(s)){
            throw new BusinessException("微信错误，调用第三个接口失败");
        }
        //将json字符串转换为wxuser对象 #字段要求一样
        Wxuser wxuser = JSONObject.parseObject(s, Wxuser.class);
        if (wxuser == null){
            throw new BusinessException("获取用户失败");
        }
        //根据手机号获取user对象
        User user = userMapper.findByPhone(dto.getPhone());
        Logininfo logininfo = new Logininfo();
        //没有查到user用户
        if (user == null){
            //添加到user表
            user = dto.getUser();
            //添加到logininfo
            BeanUtils.copyProperties(user,logininfo);
            logininfo.setType(1);
            logininfo.setDisable(true);
            logininfoMapper.add(logininfo);
            //logininfo_id
            user.setLogininfoId(logininfo.getId());
            userMapper.add(user);
        }else {//有user
            logininfo = logininfoMapper.findByuserId(user.getId());
        }
        //添加wechat
        wxuser.setUserId(user.getId());
        wxuserMapper.add(wxuser);

        Map<String, Object> map = this.getMap(logininfo);
        return AjaxResult.me().success(map);
    }


    private Map<String, Object> getMap(Logininfo logininfo) {
        // 生成token 存入到redis
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);
        // 将数据返回给前端
        // 返回数据之前 将logininfo中敏感数据 置空
        logininfo.setPassword(null);
        logininfo.setPhone(null);
        Map<String, Object> map = new HashMap<>();
        map.put("token", token);
        map.put("logininfo", logininfo);
        return map;
    }
}
